%%% Copyright 2010 Google Inc.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
%%% You may obtain a copy of the License at
%%%
%%%     http://www.apache.org/licenses/LICENSE-2.0
%%%
%%% Unless required by applicable law or agreed to in writing, software
%%% distributed under the License is distributed on an "AS IS" BASIS,
%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%%% See the License for the specific language governing permissions and
%%% limitations under the License.

%%% @copyright 2010 Google Inc. All Rights Reserved.
%%% @author <jacoby@google.com> Jacoby Thwaites [http://sites/madcloud]
%%% @version {@version}
%%% @doc
%%% Tests the graph: module against a prog_srv started with a mock
%%% prog: implementation.
%%%
%%% For more information on how unit testing works, see the following doc:
%%%
%%% [http://svn.process-one.net/contribs/trunk/eunit/doc/overview-summary.html]
-module(graph_tests).

-include_lib("eunit/include/eunit.hrl").
-include("txm.hrl").
-include("graph.hrl").

%% Test group for graph module with setup and teardown of prog_srv
%% using mock implementation.
graph_test_() ->

  % Tests can be run in parallel.
  {inparallel,

   % This tuple specifies a setup, teardown and list of test functions.
   {setup,

    % Setup starts prog_srv: against mock prog implementation. This has
    % a composition with each type of operation under {folder, {0, 20, 1}}.
    % The function returns the graph G which is used in subsequent tests
    % and cleanup.
    fun() ->
         prog_srv:start_link(prog_mock),
         {Graph, _VerticesEts, _Consumers} = graph:graph({folder, {0, 20, 1}}),
         Graph
    end,

    % Cleanup stops mock prog_srv.
    fun(G) ->
         digraph:delete(G),
         prog_srv:stop()
    end,

    % Instantiator returns (deep) list of functions. We use this form rather
    % than a literal list so that we can pass the value of the graph G.
    fun(G) ->
         [basic_tests(G),
          vertex_tests(G),
          edge_tests(G)]
    end}}.

%% Test graph creation.
basic_tests(G) ->
  [
    % Test creation by pathname.
    fun() ->
         InfoList = digraph:info(G),
         ?assert(lists:member({cyclicity, acyclic}, InfoList)),
         ?assert(lists:member({protection, protected}, InfoList))
    end,

    % Test creation by reference to "/mock/backend" which should be empty.
    fun() ->
         {G1, _VerticesEts, _Consumers} = graph:graph({folder, {0, 0, 2}}),
         ?assertEqual([], digraph:vertices(G1))
    end
    ].

%% Test vertices are correctly created.
vertex_tests(G) ->
  [
    % Test correct number of vertices are created from '/mock' composition.
    fun() ->
         ?assertEqual(5, digraph:no_vertices(G))
    end,

    % Test each vertex is labelled.
    fun() ->
      lists:foreach(
        fun(V) ->
          {V, Label} = digraph:vertex(G, V),
          ?assertMatch(#?VERTEX_LABEL{}, Label)
        end, digraph:vertices(G))
    end
    ].


%% Test edges are correctly created.
edge_tests(G) ->
  [
    % Test correct number of edges are created from '/mock' composition.
    fun() ->
         ?assertEqual(4, digraph:no_edges(G))
    end,

    % Test each edge is labelled.
    fun() ->
      lists:foreach(
        fun(E) ->
          {E, _V1, _V2, Label} = digraph:edge(G, E),
          ?assertMatch(#?EDGE_LABEL{}, Label)
        end, digraph:edges(G))
    end,

    % Test the edges have the right vertices.
    fun() ->
         % /mock graph looks like this:
         % v0 -> v1 +-> v2
         %          |-> v3
         %          +-> v4
         VPairs =
           [{['$v'|0], ['$v'|1]},
            {['$v'|1], ['$v'|2]},
            {['$v'|1], ['$v'|3]},
            {['$v'|1], ['$v'|4]}],

         lists:foreach(
           fun(E) ->
                {_E, V1, V2, _Label} = digraph:edge(G, E),
                ?assert(lists:member({V1, V2}, VPairs))
            end, digraph:edges(G))
    end
    ].
